with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;

procedure Vie is

   type Board is array(1..10,1..10) of Integer;

   State : Board ;
   Next_State : Board ;




   -- init -----------------------------------------------------------------------
   procedure Init (Grid : in out Board) is
   begin

      for Lin in Grid'Range loop
         for Col in Grid'Range loop
            Grid(Lin,Col) := 0 ;
         end loop;
      end loop;
   end Init;

   -- genesis
   procedure Genesis is
      type Numero is new Integer range 1..10 ;
      package Genesis is new Ada.Numerics.Discrete_Random (Numero);
      use Genesis;     -- Rend Generator, Reset et Random visibles
      A : Numero;
      B : Numero;
      G : Generator;

   begin
      Reset (G);          -- Initialise le générateur (à faire une seule fois)
       for I in 1..30 loop
          A := Random (G);    -- Tire un nombre au hasard entre 0 et 10
          B := Random (G);
          State(Integer(A), Integer(B)) := 1 ;
       end loop;


   end Genesis;

   -- copy -----------------------------------------------------------------------
   procedure Copy (GridOrig : Board; Outgrid : in out Board) is
   begin
      for Lin in Gridorig'Range loop
         for Col in Gridorig'Range loop
            if Lin in Outgrid'Range then
              if Col  in Outgrid'Range then
                Outgrid(Lin,Col) := GridOrig(Lin,Col);
              end if;
            end if;
         end loop;
      end loop;
   end Copy;

   -- nb of neighbour --------------------------------------------------------
   function Nb_Neighbour(Lin : Integer ; Col : Integer) return Integer is
      Nb: Integer :=0;
   begin
      -- up left
      if Lin-1 in State'Range and Col-1 in State'Range then
         if State(Lin-1,Col-1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      -- left
      if Col-1 in State'Range then
         if State(Lin,Col-1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      --down left
      if Lin+1 in State'Range and Col-1 in State'Range then
         if State(Lin+1,Col-1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      -- down
      if Lin+1 in State'Range then
         if State(Lin+1,Col) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      --down right
      if Lin+1 in State'Range and Col+1 in State'Range then
         if State(Lin+1,Col+1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      -- right
      if Col+1 in State'Range then
         if State(Lin,Col+1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      -- up right
      if Lin-1 in State'Range and Col+1 in State'Range then
         if State(Lin-1,Col+1) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      -- up
      if Lin-1 in State'Range then
         if State(Lin-1,Col) = 1 then
            Nb := Nb+ 1;
         end if ;
      end if;

      return Nb;
   end Nb_Neighbour;

   -- Display --------------------------------------------------------------------------
   procedure Display (Lifeboard : Board) is
      -- decl

      -- instruc
   begin
      for L in Lifeboard'Range loop
         for C in Lifeboard'Range loop

            Put(Integer'Image(Lifeboard(L,C)));
         end loop;

         New_Line;
      end loop;
   end Display;

   -- calcul géné_suivante --------------------------------------------------------------
   procedure Next_Generation is
      Nb : Integer := 0;
   begin
      for Lin in State'Range loop
         for Col in State'Range loop
            -- is case empty?
            if State(Lin,Col) = 0 then
               -- case empty
               -- nb_voisin
               Nb := Nb_Neighbour(Lin,Col);
               -- destroy or genesis
               if Nb= 3 then
                  Next_State(Lin,Col) := 1;
                  Put_Line("Cell at "&Integer'Image(Lin)&","&Integer'Image(Col)&" birth.");
               end if;
            else
               -- case full
               -- nb_voisin
               Nb := Nb_Neighbour(Lin,Col);
               if Nb in 2..3 then -- nb 2-3
                  Next_State(Lin,Col) := 1;
               else if Nb < 2 then -- nb <2
                  Next_State(Lin,Col) := 0;
                  Put_Line("Cell at "&Integer'Image(Lin)&","&Integer'Image(Col)&" dies alone.");
               else -- nb > 3;
                  Next_State(Lin,Col) := 0;
                  Put_line("Cell at "&Integer'Image(Lin)&","&Integer'Image(Col)&" dies by suffocation.");
               end if;
               end if;
            end if;
         end loop;
      end loop;
   end Next_Generation;

   procedure A_Generation is
   begin
      -- display generation
      Display(State);
      New_Line;
      -- calculating next generation
      Next_Generation;
      -- switch actual generation with new generation
      Copy(Next_State, State);


   end A_Generation;


   -- global
begin
   --init
   Init(State);
   Init(Next_State);

   -- genesis
   Genesis;
   -- turn
   for I in 1..50 loop
      A_Generation;
   end loop;


end Vie;
